#include <stdio.h>
#include <string.h>

#include <openssl/evp.h>
#include <openssl/sha.h>

#include "trace.h"

#define BUF_LEN (512u)

int calc_sha1(const char *filename, unsigned char **hash, unsigned int *hash_len) {
    int ret_code = 0;

    // check preconditions
    if((NULL == filename) || (NULL == hash)) {
        TRACE_ERROR("Invalid input parameters\n");
        return 1;
    }

    // prepare the file for reading using BIO
    BIO *in;
    in = BIO_new(BIO_s_file());
    if(in == NULL) {
        TRACE_ERROR("BIO_new error\n");
        return 1;
    }

    if(!BIO_read_filename(in, (char*)filename)) {
        TRACE_ERROR("BIO_read_filename error\n");
        return 2;
    }

    EVP_MD_CTX mdctx;
    const EVP_MD *md = NULL;

    OpenSSL_add_all_digests();
    md = EVP_get_digestbyname("sha1");

    EVP_MD_CTX_init(&mdctx);

    if(!EVP_DigestInit_ex(&mdctx, md, NULL)){
        TRACE_ERROR("EVP_DigestInit_ex fail\n");
        return 1;
    }

    unsigned char buf[BUF_LEN];
    int len_read;

    len_read = BIO_read(in, buf, BUF_LEN);
    TRACE_DEBUG("first read: %d\n", len_read);
    while(len_read > 0){
        if(!EVP_DigestUpdate(&mdctx, buf, len_read)){
            TRACE_ERROR("EVP_DigestUpdate fail\n");
            return 1;
        }
        len_read = BIO_read(in, buf, BUF_LEN);
        TRACE_DEBUG("read: %d\n", len_read);
    }

    if(!EVP_DigestFinal_ex(&mdctx, *hash, hash_len)){
        TRACE_ERROR("EVP_DigestFinal_ex fail\n");
        return 1;
    }

    EVP_MD_CTX_cleanup(&mdctx);

    return ret_code;
}
